package cn.louzen.utils;

import cn.louzen.domain.SampleOrg;
import cn.louzen.domain.SampleStore;
import cn.louzen.domain.SampleUser;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperledger.fabric.sdk.security.CryptoSuite;
import org.hyperledger.fabric_ca.sdk.HFCAClient;
import org.hyperledger.fabric_ca.sdk.RegistrationRequest;

import java.nio.file.Paths;
import java.util.Properties;

public class SampleUserUtil {
    private static Log logger = LogFactory.getLog(SampleUserUtil.class);

    /**
     * 调用SampleUser getSampleUser(String sampleUserName, SampleOrg sampleOrg, SampleStore sampleStore)
     *
     * @param sampleUserName
     * @param sampleOrg
     * @return
     * @throws Exception
     */
    public static SampleUser getSampleUser(String sampleUserName, SampleOrg sampleOrg) throws Exception {
        SampleStore sampleStore = SampleStore.getSampleStore();
        return getSampleUser(sampleUserName, sampleOrg, sampleStore);
    }

    /**
     * 生成组织用户，并为其注册，存入缓存，最后返回该用户
     *
     * @param sampleUserName 只能有三种情况，不然会报错，区分大小写
     *                       1：userx，user为前缀，x为数字，表示普通区块链用户
     *                       2：admin，表示区块链管理员
     *                       3：peerAdmin：表示节点管理员
     * @param sampleOrg      样例组织，里面含有组织及组织内成员的所有信息，由它提供信息配合caClient生成channel
     * @param sampleStore    基于文件的缓存，单例模式，整个系统中只有一个sampleStore实体
     * @return SampleUser
     */
    private static SampleUser getSampleUser(String sampleUserName, SampleOrg sampleOrg, SampleStore sampleStore)
            throws Exception {
        // 先检查sampleUserName的命名是否符合上述规范
        if (!(StringUtil.matchSampleUser_userx(sampleUserName) ||
                sampleUserName.equals("admin") || sampleUserName.equals("peerAdmin"))) {
            throw new Exception("SampleUser用户名不符规范！不是userx，admin，peerAdmin其中之一");
        }
        if (sampleUserName.equals("admin")) {
            return enrollAdmin(sampleUserName, sampleOrg, sampleStore);
        } else if (sampleUserName.startsWith("user")) {
            return enrollUserx(sampleUserName, sampleOrg, sampleStore);
        } else {
            return enrollPeerAdmin(sampleUserName, sampleOrg, sampleStore);
        }
    }

    // 注册admin用户
    private static SampleUser enrollAdmin(String sampleUserName, SampleOrg sampleOrg, SampleStore sampleStore)
            throws Exception {
        // 接下来检查用户是否已注册，如没有注册就用sampleOrg中的caClient注册（caClient事先要设置加密套件）
        HFCAClient caClient = sampleOrg.getCAClient();
        caClient.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
        SampleUser sampleUser = sampleStore.getMember(sampleUserName, sampleOrg.getName());
        if (!sampleUser.isEnrolled()) {
            sampleUser.setEnrollment(caClient.enroll(sampleUser.getName(), "adminpw"));
            sampleUser.setMspId(sampleOrg.getMSPID());
        } else {
            logger.info("admin已经注册(enroll)");
        }
        return sampleUser;
    }

    // 注册user用户
    private static SampleUser enrollUserx(String sampleUserName, SampleOrg sampleOrg, SampleStore sampleStore)
            throws Exception {
        // 先判断sampleOrg是否有admin用户，如果没有下面的步骤不能继续，直接抛出错误
        if (sampleOrg.getAdmin() == null) {
            throw new Exception("sampleOrg没有设置admin，不能生成user用户");
        }
        // 先从缓存中查找同名、同组织的用户，如果没有，sampleStore会创建一个
        SampleUser sampleUser = sampleStore.getMember(sampleUserName, sampleOrg.getName());
        // 接下来检查用户是否已注册，如没有注册就用sampleOrg中的caClient注册（caClient事先要设置加密套件）
        HFCAClient caClient = sampleOrg.getCAClient();
        caClient.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
        // 这个register应该就是向ca申请一个密码，user0就是账号，后续user0对账本的操作命令要附带自己的账号密码
        if (!sampleUser.isRegistered()) { // 要试一下通过caClient联系上区块链的ca容器查询user是否已经注册
            RegistrationRequest rr = new RegistrationRequest(sampleUser.getName(), "org1.department1");
            sampleUser.setEnrollmentSecret(caClient.register(rr, sampleOrg.getAdmin()));
        } else {
            logger.info(String.format("%s 已经注册(register)", sampleUserName));
        }
        if (!sampleUser.isEnrolled()) {
            sampleUser.setEnrollment(caClient.enroll(sampleUser.getName(), sampleUser.getEnrollmentSecret()));
            sampleUser.setMspId(sampleOrg.getMSPID());
        } else {
            logger.info(String.format("%s 已经注册(enroll)", sampleUserName));
        }
        return sampleUser;
    }

    // 注册peerAdmin用户
    private static SampleUser enrollPeerAdmin(String sampleUserName, SampleOrg sampleOrg, SampleStore sampleStore)
            throws Exception {
        Properties prop = Util.getProperties();
        // src/main/resources/sdkintegration/e2e-2Orgs/v1.1/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore
        // src/main/resources/sdkintegration/e2e-2Orgs/v1.1/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem
        SampleUser sampleUser = sampleStore.getMember(sampleOrg.getName() + "Admin", sampleOrg.getName(),
                sampleOrg.getMSPID(),
                Util.findFileSk(Paths
                        .get(prop.getProperty("sourcePath"), prop.getProperty("peerAdmin.privateKeyFile")).toFile()),
                Paths.get(prop.getProperty("sourcePath"), prop.getProperty("peerAdmin.certificateFile")).toFile());
        return sampleUser;
    }

}
